package m.server;

import m.server.web.req.FormData;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ReadBody {
    public static final byte[] EmptyByte=new byte[]{32};
    public static final byte[] NewLine=new byte[]{13,10};
    public static final byte[] NewDoubleLine=new byte[]{13,10,13,10};
    
    private final InputStream is;
    private byte[] surplusBytes=new byte[0];
    protected ReadBody(InputStream is){
        this.is=is;
    }

    /**
     * 读取到下一个位置并返回
     */
    public byte[] readNext(byte[] next) throws IOException {
        return readNext(next,0);
    }
    /**
     * 读取到下一个位置并返回
     * lose 丢失几位
     */
    public byte[] readNext(byte[] next,int lose) throws IOException {
        if(null==next) return new byte[0];
        byte[] bs=new byte[1024];
        int n=0,len=next.length,idx=0;
        int r;
        while(is.available()>0&&(r=is.read())>=0){
            if(bs.length==n) bs= Arrays.copyOf(bs, bs.length + 1024);
            bs[n++]=(byte) r;
            if(r==next[idx]) idx++;
            else idx=0;
            if(idx==len){
                if(lose>0){
                    for (int i=0;i<lose;i++){
                        if(is.available()>0) is.read();
                    }
                }
                bs=Arrays.copyOfRange(bs,0,n-len);
                break;
            }
        }
        return bs;
    }
    /**
     * 读取到下一个位置并返回
     */
    private byte[] readByte(byte[] next) throws IOException {
        return readByte(next,0);
    }
    /**
     * 读取到下一个位置并返回
     * lose 丢失几位
     */
    private byte[] readByte(byte[] next,int lose) throws IOException {
        if(null==next) return new byte[0];
        byte[] bs=new byte[65536];
        int si=0,len=next.length,idx=0;
        int n;
        for(byte r : this.surplusBytes){
            si++;
            if(r==next[idx]) idx++;
            else idx=0;
            if(idx==len) return splitSurplus(si,len,lose);
        }
        while (is.available()>0&&(n=is.read(bs))>=0){
            int sl=this.surplusBytes.length;
            this.surplusBytes=Arrays.copyOf(this.surplusBytes, sl + n);
            System.arraycopy(bs, 0, this.surplusBytes, sl, n);
            for(byte r : bs){
                si++;
                if(r==next[idx]) idx++;
                else idx=0;
                if(idx==len) return splitSurplus(si,len,lose);
            }
        }
        return splitSurplus(si,len,lose);
    }
    /**
     * 读取剩余全部byte
     */
    public byte[] readAllByte(int len) throws Exception {
        int sl=this.surplusBytes.length;
        int tryNum=0;
        while(is.available()<len-sl){
            tryNum++;
            if(tryNum>1000) break;
            Thread.sleep(15);
        }
        byte[] bs=new byte[len-sl];
        int n;
        while (is.available()>0&&(n=is.read(bs))>=0){
            this.surplusBytes=Arrays.copyOf(this.surplusBytes, sl + n);
            System.arraycopy(bs, 0, this.surplusBytes, sl, n);
        }
        return splitSurplus(this.surplusBytes.length,0,0);
    }
    private byte[] splitSurplus(int si,int len,int lose) throws IOException {
        byte[] result;
        if(si>=this.surplusBytes.length){
            result=Arrays.copyOfRange(this.surplusBytes,0,this.surplusBytes.length);
            this.surplusBytes=new byte[0];
        }else {
            result = Arrays.copyOfRange(this.surplusBytes, 0, si - len);
            if (si + lose <= this.surplusBytes.length) {
                this.surplusBytes = Arrays.copyOfRange(this.surplusBytes, si + lose, this.surplusBytes.length);
            } else {
                int t = si + lose - this.surplusBytes.length;
                this.surplusBytes = Arrays.copyOfRange(this.surplusBytes, si + t, this.surplusBytes.length);
                if (lose - t > 0) {
                    for (int i = 0; i < lose - t; i++) {
                        if (is.available() > 0) is.read();
                    }
                }
            }
        }
        return result;
    }

    public List<FormData> readFormData(int len,String boundary) throws Exception {
        byte[] first = ("--" + boundary + "\r\n").getBytes();//抛弃第一个分割
        int sum = readByte(first).length + first.length;
        byte[] bd = ("\r\n--" + boundary).getBytes();
        List<FormData> ls = new ArrayList<>();
        int tryNum=0;
        while (len > sum) {
            if (is.available() > 0 || this.surplusBytes.length > 0) {
                byte[] bs = readByte(ReadBody.NewDoubleLine);
                sum += bs.length + ReadBody.NewDoubleLine.length;
                String str = new String(bs);
                String[] arr = getFormDataParam(str);
                if (null == arr[0]) continue;
                byte[] content = readByte(bd, 2);
                sum += content.length + bd.length + 2;
                if (null != arr[1]) {
                    ls.add(FormData.newFile(arr[0], content, arr[1]));
                } else {
                    ls.add(FormData.newString(arr[0], content));
                }
            } else {
                tryNum++;
                if(tryNum>1000) break;
                Thread.sleep(15);
            }
        }
        return ls;
    }
    private String[] getFormDataParam(String str){
        String[] ss=str.split(";");
        String[] r=new String[2];
        for(String s : ss){
            int idx=s.indexOf("=");
            if(idx>=0){
                if(s.substring(0,idx).trim().equalsIgnoreCase("name")){
                    r[0]=getParamValue(s.substring(idx+1));
                }
                if(s.substring(0,idx).trim().equalsIgnoreCase("filename")){
                    r[1]=getParamValue(s.substring(idx+1));
                }
            }
        }
        return r;
    }
    private String getParamValue(String v){
        return v.substring(v.indexOf("\"")+1,v.lastIndexOf("\""));
    }
}
